package hessian.service;

import hession.model.LuceneDocument;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import com.caucho.hessian.server.HessianServlet;

public class LuceneServiceImpl extends HessianServlet implements LuceneService {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static IndexWriter[] writers;
	private static MultiReader multiReader;
	private static Version matchVersion = Version.LUCENE_43;
	private static Analyzer analyzer;

	@Override
	public void init() throws ServletException {
		// super.init();
		System.out.println("init....................................");
		String[] indexs = new String[] { "f:/index", "e:/index" };
		FSDirectory[] dirs = new FSDirectory[indexs.length];
		IndexReader[] readers = new IndexReader[indexs.length];
		writers = new IndexWriter[indexs.length];

		analyzer = new StandardAnalyzer(Version.LUCENE_43);
		
		IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_43, analyzer);
		iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
		iwc.setRAMBufferSizeMB(256.0);


		for (int i = 0; i < indexs.length; i++) {
			try {
				dirs[i] = FSDirectory.open(new File(indexs[i]));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		for (int i = 0; i < indexs.length; i++) {
			try {
				readers[i] = DirectoryReader.open(dirs[i]);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		multiReader = new MultiReader(readers, true);

		for (int i = 0; i < indexs.length; i++) {
			try {
				if(writers[i]!=null)
					writers[i].close();
//				writers[i] = new IndexWriter(FSDirectory.open(new File(indexs[i])), iwc);
				writers[i] = new IndexWriter(dirs[i], iwc);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public LuceneServiceImpl() throws IOException {
		System.out.println("new...............................");
	}

	@Override
	public ArrayList<LuceneDocument> doSelect(Map<String, Object> map) throws IOException {
		IndexSearcher searcher = new IndexSearcher(multiReader);
		String field = "id";
		String keyword = "*:*";
		Set<String> keySet = map.keySet();
		for (String key : keySet) {
			if ("field".equals(key)) {
				field = (String) map.get("field");
			}
			if ("keyword".equals(key)) {
				keyword = (String) map.get("keyword");
			}
			if ("analyzer".equals(key)) {
				try {
					analyzer = (Analyzer) Class.forName((String) map.get("keyword")).newInstance();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		QueryParser parser = new QueryParser(matchVersion, field, analyzer);
		ArrayList<LuceneDocument> docs = new ArrayList<LuceneDocument>();
		try {
//			Query query = parser.Query(keyword);
			 Query query = parser.parse(keyword);
			TopDocs results = searcher.search(query,null, 500);

			ScoreDoc[] hits = results.scoreDocs;
			int count = Math.min(hits.length, 500);
			for (int i = 0; i < count; i++) {
				int docId = hits[i].doc;
				float score = hits[i].score;
				int shardIndex = hits[i].shardIndex;
				LuceneDocument luceneDocument = new LuceneDocument(docId, score, shardIndex);
				Document doc = searcher.doc(docId);
				List<IndexableField> fields = doc.getFields();
				for (IndexableField indexableField : fields) {
					String key = indexableField.name();
					String value = indexableField.stringValue();
					luceneDocument.fields.put(key, value);
				}
				docs.add(luceneDocument);
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return docs;
	}

	@Override
	public void doUpdate(Map<String, String> doc) throws IOException {
		Document d = mapToDoc(doc);
		if (d != null){
			if(writers[0]==null){
				System.out.println("writers[0] is null");
			}
			writers[0].addDocument(d);
		}
	}

	@Override
	public void doUpdate(Collection<Map<String, String>> docs) throws IOException {
		writers[0].addDocuments(mapToDoc(docs));
	}

	@Override
	public void doCommit() throws IOException {
		for (int i = 0; i < writers.length; i++) {
			writers[i].commit();
		}
	}

	private Document mapToDoc(final Map<String, String> doc) {
		Document d = new Document();
		Set<String> keySet = doc.keySet();
		for (String key : keySet) {
			IndexableField field = new StringField(key, (String) doc.get(key), Store.YES);
			d.add(field);
		}
		return d;
	}

	private List<Document> mapToDoc(final Collection<Map<String, String>> docs) {
		ArrayList<Document> ds = new ArrayList<Document>();
		Iterator<Map<String, String>> it = docs.iterator();
		while (it.hasNext()) {
			ds.add(mapToDoc(it.next()));
		}
		return ds;
	}

	@Override
	public void destroy() {
		try {
			doClose();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("destroy...................");
		super.destroy();

	}

	@Override
	public void doReload() throws IOException {
		doClose();
		try {
			this.init();
		} catch (ServletException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void doClose() throws IOException {
		if (multiReader != null)
			multiReader.close();
		for (int i = 0; i < writers.length; i++) {
			if (writers[i] != null)
				writers[i].close();
		}
	}

}
